﻿Public Class Game
    Public State As GameState = GameState.MainMenu
    Public ScreenToDisplay As IScreen
    Public Players(4) As Player
    Private CurrentPlayerTurnIndex As Integer = 0

    Private WithEvents GameplayScreen As Gameplay

    Private WithEvents AITimer As New Timers.Timer(2000)

    Public ReadOnly Property CurrentPlayerTurn() As Integer
        Get
            Return CurrentPlayerTurnIndex + 1
        End Get
    End Property

    Public ReadOnly Property CurrentPlayer() As Player
        Get
            Return Players(CurrentPlayerTurnIndex)
        End Get
    End Property

    Public Sub EndTurn()
        'need to check if someone won
        
        If (CheckForGameOver() = False) Then
            AdvanceCurrentPlayerTurnIndex()
            While (CurrentPlayer.CheckIfDead() = True)
                AdvanceCurrentPlayerTurnIndex()
            End While
            GameplayScreen.SetPlayerTurn(CurrentPlayer)
            If (CurrentPlayer.HumanControlled = False) Then
                AITimer.Start()
            End If
        Else
            DisplayGameOverScreen()
        End If

    End Sub

    Private Sub ComputerTurn()

        Select Case CurrentPlayer.DeterminePlayerAction()
            Case PlayerAction.Attack
                If (CurrentPlayer.CanBomb()) Then
                    Dim playerToAttack As Integer = CurrentPlayer.GetPlayerToAttack()
                    Bomb(CurrentPlayer, CurrentPlayer.BestAvailableWarheadToBomb(), Players(playerToAttack).Cities.RandomCity, Players(playerToAttack))
                ElseIf (CurrentPlayer.CanLaunchMissile()) Then
                    Dim playerToAttack As Integer = CurrentPlayer.GetPlayerToAttack()
                    LaunchMissile(CurrentPlayer, CurrentPlayer.BestAvailableWarheadToLaunch(), Players(playerToAttack).Cities.RandomCity, Players(playerToAttack))
                ElseIf (CurrentPlayer.MissileDeployed = MissileAndWarheadTypes.None And CurrentPlayer.BestAvailableMissileToDeploy <> MissileAndWarheadTypes.None) Then
                    DeployMissile(CurrentPlayer, CurrentPlayer.BestAvailableMissileToDeploy())
                ElseIf (CurrentPlayer.BomberDeployed = False And CurrentPlayer.Inventory.Bombers > 0) Then
                    DeployBomber(CurrentPlayer)
                Else
                    EndTurn()
                End If
            Case PlayerAction.Build
                Build(CurrentPlayer)
            Case PlayerAction.Defend
                If (CurrentPlayer.Inventory.AntiMissile > 1 And CurrentPlayer.AntiMissileDeployed = False) Then
                    DeployAntiMissile(CurrentPlayer)
                ElseIf (CurrentPlayer.Inventory.AntiAircraft > 1 And CurrentPlayer.AntiAircraftDeployed = False) Then
                    DeployAntiAircraft(CurrentPlayer)
                Else
                    EndTurn()
                End If
            Case PlayerAction.Propoganda
                RandomNumberProvider.CheckIfChanceOccurs(30)
                Dim playerToAttack As Integer = CurrentPlayer.GetPlayerToAttack()
                Propaganda(CurrentPlayer, Players(playerToAttack).Cities.RandomCity, Players(playerToAttack))
        End Select

    End Sub

    Public Function CheckForGameOver() As Boolean
        Dim alivePlayers As Integer = 0
        For Each player As Player In Players
            If (player.CheckIfDead() = False) Then
                alivePlayers += 1
            End If
        Next

        If (alivePlayers > 1) Then
            Return False
        Else
            Return True
        End If
    End Function

    Private Sub AdvanceCurrentPlayerTurnIndex()
        CurrentPlayerTurnIndex += 1
        If (CurrentPlayerTurnIndex > 4) Then
            CurrentPlayerTurnIndex = 0
        End If
    End Sub

    Public Sub New()
        PreLoadRequiredItems()

        DisplayMainMenuScreen()
    End Sub

    Private Sub PreLoadRequiredItems()
        CommonSurfaces.Instance()
    End Sub

    Private Sub DisplayMainMenuScreen()
        DisposeOfCurrentScreen()

        State = GameState.MainMenu
        Dim mainMenu As New MainMenu()
        AddHandler mainMenu.RequestedQuit, AddressOf Quit
        AddHandler mainMenu.RequestedNewGame, AddressOf DisplayCharacterSelectScreen

        ScreenToDisplay = mainMenu
    End Sub

    Private Sub DisplayCharacterSelectScreen()
        DisposeOfCurrentScreen()

        State = GameState.CharacterSelect
        Dim characterSelect As New CharacterSelect()
        AddHandler characterSelect.AllAvatarsSelected, AddressOf StartNewGame
        AddHandler characterSelect.RequestReturnToMainMenu, AddressOf DisplayMainMenuScreen

        ScreenToDisplay = characterSelect
    End Sub

    Private Sub DisplayGameOverScreen()
        DisposeOfCurrentScreen()

        State = GameState.GameOver
        Dim gameOver As New GameOver(Players)
        AddHandler gameOver.RequestedQuit, AddressOf Quit
        AddHandler gameOver.RequestedNewGame, AddressOf DisplayCharacterSelectScreen

        ScreenToDisplay = gameOver
    End Sub

    Private Sub DisposeOfCurrentScreen()
        If (ScreenToDisplay IsNot Nothing) Then
            ScreenToDisplay.Dispose()
        End If
    End Sub


    Private Sub StartNewGame(ByVal players() As Player)
        Me.Players = players

        DisposeOfCurrentScreen()

        GameplayScreen = New Gameplay(players, players(0))
        AddHandler GameplayScreen.Build, AddressOf Build
        AddHandler GameplayScreen.Propaganda, AddressOf Propaganda
        AddHandler GameplayScreen.DeployMissile, AddressOf DeployMissile
        AddHandler GameplayScreen.LaunchMissile, AddressOf LaunchMissile
        AddHandler GameplayScreen.MissileDestroyedByAntiMissile, AddressOf MissileDestroyedByAntiMissile
        AddHandler GameplayScreen.DeployAntiMissile, AddressOf DeployAntiMissile
        AddHandler GameplayScreen.DeployAntiAircraft, AddressOf DeployAntiAircraft
        AddHandler GameplayScreen.DeployBomber, AddressOf DeployBomber
        AddHandler GameplayScreen.Bomb, AddressOf Bomb
        ScreenToDisplay = GameplayScreen
        If (CurrentPlayer.HumanControlled = False) Then
            AITimer.Start()
        End If
    End Sub

    Private Sub Quit()
        State = GameState.Quit
    End Sub

    Public Sub DeployBomber(ByRef player As Player)
        player.BomberDeployed = True
        AddHandler player.DeployedBomber.NuclearExplosion, AddressOf GameplayScreen.CreateNuclearExplosion
        AddHandler player.DeployedBomber.Explosion, AddressOf GameplayScreen.CreateExplosion
        AddHandler player.DeployedBomber.BomberDestroyedByAntiAircraft, AddressOf BomberDestroyedByAntiAircraft
        GameplayScreen.AddCurrentPlayerMessageToInformation("deployed bomber!")

        EndTurn()
    End Sub

    Public Sub DeployAntiAircraft(ByRef player As Player)
        player.AntiAircraftDeployed = True
        GameplayScreen.AddCurrentPlayerMessageToInformation("deployed anti-aircraft.")

        EndTurn()
    End Sub

    Public Sub DeployAntiMissile(ByRef player As Player)
        player.AntiMissileDeployed = True
        GameplayScreen.AddCurrentPlayerMessageToInformation("deployed anti-missile.")

        EndTurn()
    End Sub

    Public Sub BomberDestroyedByAntiAircraft(ByRef defendingPlayer As Player, ByRef bomberOwner As Player)
        bomberOwner.BomberDeployed = False
        bomberOwner.DeployedBomber = Nothing
        bomberOwner.Inventory.Bombers -= 1
        defendingPlayer.Inventory.AntiAircraft -= 1
        defendingPlayer.AntiAircraftDeployed = False

        GameplayScreen.AddTextToInformationWindow("Bomber destroyed by anti-aircraft!")
    End Sub

    Public Sub MissileDestroyedByAntiMissile(ByRef defendingPlayer As Player)
        defendingPlayer.Inventory.AntiMissile -= 1
        defendingPlayer.AntiMissileDeployed = False

        GameplayScreen.AddTextToInformationWindow("Missile destroyed by anti-missile!")
    End Sub

    Public Sub LaunchMissile(ByRef player As Player, ByVal warheadType As MissileAndWarheadTypes, ByRef targetCIty As City, ByRef targetPlayer As Player)
        UsedWarhead(player, warheadType)

        If (player.MissileDeployed = MissileAndWarheadTypes.ExtraLarge) Then
            player.Inventory.ExtraLargeMissiles -= 1
        ElseIf (player.MissileDeployed = MissileAndWarheadTypes.Large) Then
            player.Inventory.LargeMissiles -= 1
        ElseIf (player.MissileDeployed = MissileAndWarheadTypes.Medium) Then
            player.Inventory.MediumMissiles -= 1
        ElseIf (player.MissileDeployed = MissileAndWarheadTypes.Small) Then
            player.Inventory.SmallMissiles -= 1
        End If

        Dim damageToDo As Integer = WarheadDamageProvider.CalculateDamage(warheadType)

        GameplayScreen.CreateMissile(player.CommandCenter.Position, targetCIty, targetPlayer, damageToDo)


        player.MissileDeployed = MissileAndWarheadTypes.None
        GameplayScreen.AddCurrentPlayerMessageToInformation("has fired!.")

        EndTurn()
    End Sub

    Public Sub Bomb(ByRef player As Player, ByVal warheadType As MissileAndWarheadTypes, ByRef targetCIty As City, ByRef targetPlayer As Player)
        UsedWarhead(player, warheadType)

        Dim amountOfDamageToDo As Integer = WarheadDamageProvider.CalculateDamage(warheadType)
        player.DeployedBomber.BombTarget(targetPlayer, targetCIty, amountOfDamageToDo)

        GameplayScreen.AddCurrentPlayerMessageToInformation("is bombing!")
        EndTurn()
    End Sub

    Public Sub DeployMissile(ByRef player As Player, ByVal type As MissileAndWarheadTypes)
        CurrentPlayer.MissileDeployed = type
        GameplayScreen.AddCurrentPlayerMessageToInformation("deployed a missile!")

        EndTurn()
    End Sub

    Public Sub Propaganda(ByRef player As Player, ByRef targetCity As City, ByRef targetPlayer As Player)
        GameplayScreen.AddCurrentPlayerMessageToInformation("is broadcasting!")
        If (targetCity.Health > 0) Then
            Dim numberOfPeople As Integer = 0

            Dim randomOutcome As Integer = RandomNumberProvider.GetRandomNumber(1, 100)
            If (randomOutcome < 5) Then
                numberOfPeople = CInt(targetCity.Health * 0.5)
            ElseIf (randomOutcome < 35) Then
                numberOfPeople = CInt(targetCity.Health * 0.3)
            ElseIf (randomOutcome < 60) Then
                numberOfPeople = CInt(targetCity.Health * 0.2)
            ElseIf (randomOutcome < 85) Then
                numberOfPeople = CInt(targetCity.Health * 0.1)
            End If

            Dim modifier As Integer = RandomNumberProvider.GetRandomNumber(-5, 5)
            numberOfPeople += modifier

            If (numberOfPeople > 0) Then
                GameplayScreen.AddTextToInformationWindow(numberOfPeople & " left Player " & targetPlayer.PlayerNumber & "!")
                GameplayScreen.CreatePlayerMigration(targetCity, player.Cities.RandomCity(), numberOfPeople)
            End If
        End If

        EndTurn()
    End Sub

    Public Sub Build(ByRef player As Player)
        Dim amountToAdd As Integer = RandomNumberProvider.GetRandomNumber(1, 3)

        If (RandomNumberProvider.CheckIfChanceOccurs(20)) Then
            If (RandomNumberProvider.CheckIfChanceOccurs(50)) Then
                player.Inventory.AntiMissile += amountToAdd
            Else
                player.Inventory.AntiAircraft += amountToAdd
            End If
        End If

        If (RandomNumberProvider.CheckIfChanceOccurs(15)) Then
            player.Inventory.Bombers += amountToAdd
        End If

        If (RandomNumberProvider.CheckIfChanceOccurs(70)) Then
            Dim gotAMissile As Boolean = False
            If (RandomNumberProvider.CheckIfChanceOccurs(35)) Then
                gotAMissile = True
                player.Inventory.ExtraLargeMissiles += amountToAdd
            End If
            If (RandomNumberProvider.CheckIfChanceOccurs(55)) Then
                gotAMissile = True
                player.Inventory.LargeMissiles += amountToAdd
            End If
            If (RandomNumberProvider.CheckIfChanceOccurs(60)) Then
                gotAMissile = True
                player.Inventory.MediumMissiles += amountToAdd + 1
            End If
            If (RandomNumberProvider.CheckIfChanceOccurs(60)) Then
                gotAMissile = True
                player.Inventory.SmallMissiles += amountToAdd + 1
            End If

            If (gotAMissile = False) Then
                If (RandomNumberProvider.CheckIfChanceOccurs(65)) Then
                    player.Inventory.SmallMissiles += amountToAdd
                Else

                    player.Inventory.MediumMissiles += amountToAdd
                End If
            End If
        End If

        If (RandomNumberProvider.CheckIfChanceOccurs(70)) Then
            Dim gotAWarhead As Boolean = False
            If (RandomNumberProvider.CheckIfChanceOccurs(35)) Then
                gotAWarhead = True
                player.Inventory.ExtraLargeWarheads += amountToAdd
            End If
            If (RandomNumberProvider.CheckIfChanceOccurs(55)) Then
                gotAWarhead = True
                player.Inventory.LargeWarheads += amountToAdd
            End If
            If (RandomNumberProvider.CheckIfChanceOccurs(60)) Then
                gotAWarhead = True
                player.Inventory.MediumWarheads += amountToAdd + 1
            End If
            If (RandomNumberProvider.CheckIfChanceOccurs(60)) Then
                gotAWarhead = True
                player.Inventory.SmallWarheads += amountToAdd + 1
            End If

            If (gotAWarhead = False) Then
                If (RandomNumberProvider.CheckIfChanceOccurs(65)) Then
                    player.Inventory.SmallWarheads += amountToAdd
                Else

                    player.Inventory.MediumWarheads += amountToAdd
                End If
            End If
        End If

        GameplayScreen.AddCurrentPlayerMessageToInformation("is building.")

        EndTurn()
    End Sub

    Private Sub UsedWarhead(ByRef player As Player, ByVal warheadType As MissileAndWarheadTypes)
        If (warheadType = MissileAndWarheadTypes.ExtraLarge) Then
            player.Inventory.ExtraLargeWarheads -= 1
        ElseIf (warheadType = MissileAndWarheadTypes.Large) Then
            player.Inventory.LargeWarheads -= 1
        ElseIf (warheadType = MissileAndWarheadTypes.Medium) Then
            player.Inventory.MediumWarheads -= 1
        ElseIf (warheadType = MissileAndWarheadTypes.Small) Then
            player.Inventory.SmallWarheads -= 1
        End If
    End Sub

    Private Sub TEST_MAKE_GAME_OVER_WINNER()
        For Each p As Player In Players
            For Each c As City In p.Cities.cities
                c.Health = 0
            Next
        Next

        Players(0).Cities.cities(0).Health = 10
    End Sub

    Private Sub AITimer_Elapsed(ByVal sender As Object, ByVal e As System.Timers.ElapsedEventArgs) Handles AITimer.Elapsed
        AITimer.Stop()
        ComputerTurn()
    End Sub
End Class
